package http

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/didi/nightingale/src/common/dataobj"
	"github.com/didi/nightingale/src/models"
	"github.com/didi/nightingale/src/modules/agent/config"
	"github.com/didi/nightingale/src/modules/agent/core"
	"github.com/didi/nightingale/src/modules/agent/ecache"
	"github.com/didi/nightingale/src/modules/agent/log/strategy"
	"github.com/didi/nightingale/src/modules/agent/log/worker"
	"github.com/didi/nightingale/src/modules/agent/report"
	"github.com/didi/nightingale/src/modules/agent/stra"
	"github.com/didi/nightingale/src/modules/agent/sys/checks"
	"github.com/didi/nightingale/src/modules/agent/sys/services"
	"github.com/gin-gonic/gin"
	"github.com/toolkits/pkg/errors"
	"github.com/toolkits/pkg/logger"
	"strings"
	"time"
)

func pushData(c *gin.Context) {
	if c.Request.ContentLength == 0 {
		renderMessage(c, "blank body")
		return
	}

	var recvMetricValues []*dataobj.MetricValue
	errors.Dangerous(c.ShouldBindJSON(&recvMetricValues))

	err := core.Push(recvMetricValues)
	renderMessage(c, err)
}

func getStrategy(c *gin.Context) {
	var resp []interface{}

	port := stra.GetPortCollects()
	for _, p := range port {
		resp = append(resp, p)
	}

	proc := stra.GetProcCollects()
	for _, p := range proc {
		resp = append(resp, p)
	}

	service := stra.GetServiceCollects()
	for _, s := range service {
		resp = append(resp, s)
	}

	check := stra.GetCheckCollects()
	for _, c := range check {
		resp = append(resp, c)
	}

	logStras := strategy.GetListAll()
	for _, s := range logStras {
		resp = append(resp, s)
	}

	renderData(c, resp, nil)
}

func getLogCached(c *gin.Context) {
	renderData(c, worker.GetCachedAll(), nil)
}

func pushLabelData(c *gin.Context) {
	var recv json.RawMessage
	errors.Dangerous(c.ShouldBind(&recv))

	var kv map[string]interface{}
	err := json.Unmarshal(recv, &kv)
	b, _ := json.Marshal(kv)
	logger.Infof("receive label: %+v", string(b))
	if err != nil {
		logger.Errorf("pushLabel json Unmarshal %v error, err=%v", recv, err)
		errors.Dangerous(err)
	}
	for k, v := range kv {
		ecache.LabelCache.SetByKey(k, v)
	}
	buf := &bytes.Buffer{}
	buf.WriteString("ok")
	renderData(c, buf.String(), err)
}

func pushEventData(c *gin.Context) {
	var recv json.RawMessage
	errors.Dangerous(c.ShouldBind(&recv))
	var collects []*dataobj.Watcher
	err := json.Unmarshal(recv, &collects)
	if err != nil {
		errors.Dangerous(err)
	}
	for _, col := range collects {
		var fileKind string
		if col.FileInfo == nil {
			fileKind = "未知"
		} else {
			fileKind = col.FileInfo.Kind
		}
		if !strings.Contains(col.EventPath, "log") {
			event := dataobj.EventInfo{
				Hostname:  col.Hostname,
				Node:      stra.Collect.Node,
				IP:        report.IP,
				Level:     col.LogLevel,
				Checktime: formatTime(col.EventTime),
				Info:      fmt.Sprintf("%v %v %v", fileKind, col.EventPath, col.EventKind),
			}
			data := map[string]interface{}{
				"hostname": config.Endpoint,
				"envtype":  "event",
				"node":     stra.Collect.Node,
				"doc":      event,
				"labels":   ecache.LabelCache.GetAll(),
			}
			err = report.ReportTransferData(data, false)
			if err != nil {
				logger.Errorf("event report: %+v, err: %+v", data, err)
			}
		}
	}

	buf := &bytes.Buffer{}
	buf.WriteString("ok")
	renderData(c, buf.String(), err)
}

func pushServiceData(c *gin.Context) {
	var recv dataobj.ServiceInfo
	errors.Dangerous(c.ShouldBind(&recv))
	//recv.Checktime = formatTime(recv.Checktime)
	data := map[string]interface{}{
		"hostname": config.Endpoint,
		"envtype":  "service",
		"node":     stra.Collect.Node,
		"doc":      recv, //这个就是刚才给的environment的里的一部分，比如cron，就上传CronInfo的json; service就是ServiceInfo, "general|personal",就是CheckInfo
		"labels":   ecache.LabelCache.GetAll(),
	}
	logger.Debugf("service report: %+v", data)
	buf := &bytes.Buffer{}
	err := report.ReportTransferData(data, true)
	if err != nil {
		logger.Errorf("service data=%+v report error:%v", data, err)
		renderData(c, "", err)
		return
	}

	buf.WriteString("ok")
	renderData(c, buf.String(), err)
}

func pushCronData(c *gin.Context) {
	var recv []*dataobj.CronInfo
	errors.Dangerous(c.ShouldBind(&recv))
	data := map[string]interface{}{
		"hostname": config.Endpoint,
		"envtype":  "cron",
		"node":     stra.Collect.Node,
		"doc":      recv, //这个就是刚才给的environment的里的一部分，比如cron，就上传CronInfo的json; service就是ServiceInfo, "general|personal",就是CheckInfo
		"labels":   ecache.LabelCache.GetAll(),
	}
	logger.Debugf("cron report: %+v", data)
	err := report.ReportTransferData(data, true)
	if err != nil {
		logger.Errorf("cron data=%+v report error:%v", data, err)
		renderData(c, "", err)
		return
	}
	buf := &bytes.Buffer{}
	buf.WriteString("ok")
	renderData(c, buf.String(), err)
}

func runService(c *gin.Context) {
	var recv models.ServiceCollect
	errors.Dangerous(c.ShouldBind(&recv))
	go func() {
		logger.Debugf("manual run service collect: %+v", recv.Name)
		services.ServiceRun(&recv)
		logger.Debugf("manual run service collect: %+v success", recv.Name)
	}()
	buf := &bytes.Buffer{}
	buf.WriteString("ok")
	renderData(c, buf.String(), nil)
}

func runCheck(c *gin.Context) {
	var recv models.CheckCollect
	errors.Dangerous(c.ShouldBind(&recv))
	go func() {
		logger.Debugf("manual run check collect: %+v", recv.Name)
		checks.CheckRun(&recv)
		logger.Debugf("manual run check collect: %+v success", recv.Name)
	}()
	buf := &bytes.Buffer{}
	buf.WriteString("ok")
	renderData(c, buf.String(), nil)
}

func formatTime(timeStr string) string {
	duetimecst, _ := time.ParseInLocation("2006-01-02 15:04:05", timeStr, time.Local)
	return duetimecst.Format("2006-01-02T15:04:05+0800")
}
